/* 
 * File:   UnitOfWork.cpp
 * Author: maximiliano
 * 
 * Created on March 26, 2013, 5:42 PM
 */

#include "UnitOfWork.h"
#include "Print.h"
#include "Revert.h"

using namespace TP3::Working;

UnitOfWork::UnitOfWork(ostream* outPut) {
    _outPut = outPut;
}

UnitOfWork::~UnitOfWork() {
    
    deleteMangles();
    deleteStates();
    _outPut = NULL;
}

void UnitOfWork::deleteStates(){

    // Elimino el conjunto de estados.

    string* actual = (string*)_operationStates.Primero();
    string* kill = NULL;
    
    while (NULL != actual)
    {
        kill = actual;
        actual = (string*)_operationStates.Siguiente(actual);
        delete kill;
    }
    _operationStates.Limpiar();
}

void UnitOfWork::deleteMangles(){

    // Elimino el conjunto de mangles.
    
    Mangle* actual = (Mangle*)_mangles.Primero();
    Mangle* kill = NULL;
    
    while (NULL != actual)
    {
        kill = actual;
        actual = (Mangle*)_mangles.Siguiente(actual);
        delete kill;
    }
    _mangles.Limpiar();
}

string UnitOfWork::undo(){

    string* lastState = (string*) _operationStates.Ultimo();
    
    if (_operationStates.Count() > 1)
    {
        _operationStates.Remover(lastState);
        delete lastState;
        lastState = (string*) _operationStates.Ultimo();
    }
    
    return *lastState;
}

string& UnitOfWork::apply (string& operating){
    
    /* Inicializo el monitor de estados.
     * 
     * Para todo Mangle declarado =>
     *  1) Aplico el Mangle.
     *  2) Configuro el nuevo estado.
     * 
     * Luego, retorno el estado actual.
     * 
     */
    
    initStateMonitor(operating);
    
    void* mangle = _mangles.Primero();
    
    while (NULL != mangle)
    {
        ((Mangle*) mangle)->run(operating);
        
        if (hasChanged(operating))
            setNewState (operating);
        
        mangle = _mangles.Siguiente(mangle);
    }
    
    return operating;
}

Mangle* UnitOfWork::addMangle (Mangle* mangle){

    if (mangle->getName() == "print")
        ((Print*) mangle)->setOutput(_outPut);
    
    else if (mangle->getName() == "revert")
    {
        ((Revert*) mangle)->setUnitOfWork(this);
    }
    
    _mangles.Agregar(mangle);
    return mangle;
}

string& UnitOfWork::initStateMonitor (string& operating){
    
    deleteStates();
    
    return setNewState (operating);
}

string& UnitOfWork::setNewState (string& operating){
    
    // Clono el operando.
    string* state = new string();
    *state = operating;
    
    // Declaro el clon como el nuevo estado.
    _operationStates.Agregar(state);
    
    return operating;
}

string UnitOfWork::getCurrentState (){
    
    string* state = (string*) _operationStates.Ultimo();
    return *state;
}

bool UnitOfWork::hasChanged(string& operating){
    
    string* previousState = (string*) _operationStates.Ultimo();
    return  *previousState != operating;
}

